package service

import (
	"bytes"
	"certificate/global"
	"certificate/token"
	"certificate/vo"
	"encoding/json"
	"fmt"
	"github.com/spf13/viper"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

type Douyin struct {
	AccessToken string
}

func NewDouyin() (*Douyin, error) {
	accessToken, err := token.GetDouYinAccessToken()
	if err != nil {
		global.Log.Error(err.Error())
		return nil, err
	}
	return &Douyin{
		AccessToken: accessToken.AccessToken,
	}, nil
}

// Prepare 验券准备
func (d Douyin) Prepare(prepare vo.DouYinCertificatePrepare) (map[string]any, error) {
	baseUrl := viper.GetString("douyin.certificate.prepare.apiUrl")
	method := viper.GetString("douyin.certificate.prepare.method")

	params := url.Values{}
	if prepare.EncryptedData != "" {
		params.Add("encrypted_data", prepare.EncryptedData)
	}
	if prepare.Code != "" {
		params.Add("code", prepare.Code)
	}
	if prepare.PoiId != "" {
		params.Add("poi_id", prepare.PoiId)
	}

	encodedParams := params.Encode()
	encodedParams = strings.ReplaceAll(encodedParams, "+", "%2B")

	reqURL := fmt.Sprintf("%s?%s", baseUrl, encodedParams)

	req, err := http.NewRequest(method, reqURL, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("access-token", d.AccessToken)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	var data = make(map[string]any)
	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// Verify 验券
func (d Douyin) Verify(verify vo.DouYinCertificateVerify) (map[string]any, error) {

	baseUrl := viper.GetString("douyin.certificate.verify.apiUrl")
	method := viper.GetString("douyin.certificate.verify.method")

	requestBody, err := json.Marshal(verify)

	req, err := http.NewRequest(method, baseUrl, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("access-token", d.AccessToken)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	var data = make(map[string]any)
	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// Cancel 撤销核验
func (d Douyin) Cancel(cancel vo.DouYinCertificateCancel) (map[string]any, error) {

	baseUrl := viper.GetString("douyin.certificate.cancel.apiUrl")
	method := viper.GetString("douyin.certificate.cancel.method")

	requestBody, err := json.Marshal(cancel)

	req, err := http.NewRequest(method, baseUrl, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("access-token", d.AccessToken)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	var data = make(map[string]any)
	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

// Get 获取券状态
func (d Douyin) Get(douGet vo.DouYinCertificateGet) (map[string]any, error) {

	baseUrl := viper.GetString("douyin.certificate.get.apiUrl")
	method := viper.GetString("douyin.certificate.get.method")

	params := url.Values{}
	params.Add("encrypted_code", douGet.EncryptedCode)
	encodedParams := params.Encode()
	encodedParams = strings.ReplaceAll(encodedParams, "+", "%2B")

	reqURL := fmt.Sprintf("%s?%s", baseUrl, encodedParams)

	req, err := http.NewRequest(method, reqURL, nil)

	if err != nil {
		return nil, err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("access-token", d.AccessToken)

	client := &http.Client{}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	var data = make(map[string]any)
	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return data, nil
}
